/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package pa165.dominatingspecies.rest;

import com.owlike.genson.ext.jersey.GensonJsonConverter;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JScrollPane;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.Invocation;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.GenericType;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.client.filter.HttpBasicAuthFilter;
import pa165.dominating.species.tos.ElementTo;
import pa165.dominating.species.tos.EnvironmentTo;

/**
 *
 * @author Stanislau Dubrouski
 */
public class EnvironmentsPanel extends javax.swing.JPanel {

    private final ClientConfig cfg = new ClientConfig(GensonJsonConverter.class);
    private static final int ID_COLUMN_POSITION = 0;
    private static final String restUrl = "http://localhost:8080/pa165/rest";

    /**
     * Creates new form EnvironmentsPanel
     */
    public EnvironmentsPanel() {
        cfg.register(new HttpBasicAuthFilter("rest","rest"));
        initComponents();
        initTable();
        initElemsTable();
        this.setName("Environments");
        updateButton.setEnabled(false);
    }

    private void initTable() {
        environmentsTable.setModel(new EnvironmentTableModel());
        environmentsTable.setColumnSelectionAllowed(false);
        environmentsTable.setRowSelectionAllowed(true);
        environmentsTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        jScrollPane3.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
        jScrollPane3.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
        outputTextArea.setLineWrap(true);

        environmentsTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
            @Override
            public void valueChanged(ListSelectionEvent e) {
                changeButton.setEnabled(true);
                updateButton.setEnabled(false);
                outputTextArea.setText("");
                elemsTable.clearSelection();
                descTextArea.setText("");
                nameTextField.setText("");
            }
        });
        getEnvironmentsData();
    }
    
    private void initElemsTable(){
        elemsTable.setModel(new ElementTableModel());
        elemsTable.setColumnSelectionAllowed(false);
        elemsTable.setRowSelectionAllowed(true);
        elemsTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
        
        getElementsData();
    }
    
    private void getElementsData(){
        Client client = ClientBuilder.newClient(cfg);
        WebTarget webTarget = client.target(restUrl);
        WebTarget resourceWebTarget = webTarget.path("elements");

        Invocation.Builder invocationBuilder = resourceWebTarget.request(MediaType.APPLICATION_JSON);
        invocationBuilder.header("accept", "application/json");

        int respStat = -1;
        List<ElementTo> lists = null;
        try {
            Response response = invocationBuilder.get();
            respStat = response.getStatus();

            lists = response.readEntity(new GenericType<List<ElementTo>>() {
            });
            for (ElementTo ele : lists) {
                ((ElementTableModel) elemsTable.getModel()).addElementToTable(ele);
            }

        } catch (javax.ws.rs.ProcessingException e) {
            System.out.println("Cannot connect to server.");
            disableButtons();
            outputTextArea.setText("Cannot connect to server!");
        }
        if (respStat == 204) {
            outputTextArea.setText("No data on the server!");
        }
        if (respStat == 200) {
            outputTextArea.setText("Data successfully loaded!");
        }
        if ((respStat != 200) && (respStat != 204)) {
            outputTextArea.setText("Unknown error occured, please restart application.");
        }
        if ((respStat == 200) && (lists != null) && (lists.isEmpty())) {
            outputTextArea.setText("No elements in DB");
        }
    }
    
    public void update(){
        elemsTable.setModel(new ElementTableModel());
        getElementsData();
    }
    
    private void getEnvironmentsData() {

        Client client = ClientBuilder.newClient(cfg);
        WebTarget webTarget = client.target(restUrl);
        WebTarget resourceWebTarget = webTarget.path("environments");

        Invocation.Builder invocationBuilder = resourceWebTarget.request(MediaType.APPLICATION_JSON);
        invocationBuilder.header("accept", "application/json");

        int respStat = -1;
        List<EnvironmentTo> lists = null;
        try {
            Response response = invocationBuilder.get();
            respStat = response.getStatus();

            lists = response.readEntity(new GenericType<List<EnvironmentTo>>() {
            });
            for (EnvironmentTo env : lists) {
                ((EnvironmentTableModel) environmentsTable.getModel()).addEnvironmentToTable(env);
            }

        } catch (javax.ws.rs.ProcessingException e) {
            System.out.println("Cannot connect to server.");
            disableButtons();
            outputTextArea.setText("Cannot connect to server!");
        }
        if (respStat == 204) {
            outputTextArea.setText("No data on the server!");
        }
        if (respStat == 200) {
            outputTextArea.setText("Data successfully loaded!");
        }
        if ((respStat != 200) && (respStat != 204)) {
            outputTextArea.setText("Unknown error occured, please restart application.");
        }
        if ((respStat == 200) && (lists != null) && (lists.isEmpty())) {
            outputTextArea.setText("No environments in DB");
        }

    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        envsScrollPane = new javax.swing.JScrollPane();
        environmentsTable = new javax.swing.JTable();
        leftSidePanel = new javax.swing.JPanel();
        jLabel1 = new javax.swing.JLabel();
        nameTextField = new javax.swing.JTextField();
        jLabel2 = new javax.swing.JLabel();
        jScrollPane2 = new javax.swing.JScrollPane();
        descTextArea = new javax.swing.JTextArea();
        createButton = new javax.swing.JButton();
        updateButton = new javax.swing.JButton();
        changeButton = new javax.swing.JButton();
        jLabel3 = new javax.swing.JLabel();
        jScrollPane3 = new javax.swing.JScrollPane();
        outputTextArea = new javax.swing.JTextArea();
        jLabel4 = new javax.swing.JLabel();
        jScrollPane4 = new javax.swing.JScrollPane();
        elemsTable = new javax.swing.JTable();
        detailsButton = new javax.swing.JButton();
        deleteButton = new javax.swing.JButton();

        setMinimumSize(new java.awt.Dimension(200, 200));
        setPreferredSize(new java.awt.Dimension(700, 500));

        environmentsTable.setModel(new javax.swing.table.DefaultTableModel(
            new Object [][] {
                {null, null, null, null},
                {null, null, null, null},
                {null, null, null, null},
                {null, null, null, null}
            },
            new String [] {
                "Title 1", "Title 2", "Title 3", "Title 4"
            }
        ));
        envsScrollPane.setViewportView(environmentsTable);

        leftSidePanel.setPreferredSize(new java.awt.Dimension(300, 400));

        jLabel1.setText("Name");

        jLabel2.setText("Description");

        descTextArea.setColumns(20);
        descTextArea.setRows(2);
        descTextArea.setAutoscrolls(false);
        jScrollPane2.setViewportView(descTextArea);
        descTextArea.getAccessibleContext().setAccessibleParent(leftSidePanel);

        createButton.setText("Create");
        createButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                createButtonActionPerformed(evt);
            }
        });

        updateButton.setText("Update");
        updateButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                updateButtonActionPerformed(evt);
            }
        });

        changeButton.setText("Change...");
        changeButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                changeButtonActionPerformed(evt);
            }
        });

        jLabel3.setText("Output");

        outputTextArea.setColumns(20);
        outputTextArea.setRows(5);
        outputTextArea.setCursor(new java.awt.Cursor(java.awt.Cursor.TEXT_CURSOR));
        outputTextArea.setFocusable(false);
        jScrollPane3.setViewportView(outputTextArea);
        outputTextArea.getAccessibleContext().setAccessibleParent(leftSidePanel);

        jLabel4.setText("Elements");

        elemsTable.setModel(new javax.swing.table.DefaultTableModel(
            new Object [][] {
                {null, null, null, null},
                {null, null, null, null},
                {null, null, null, null},
                {null, null, null, null}
            },
            new String [] {
                "Title 1", "Title 2", "Title 3", "Title 4"
            }
        ));
        elemsTable.setMinimumSize(new java.awt.Dimension(300, 150));
        elemsTable.setPreferredSize(new java.awt.Dimension(300, 150));
        elemsTable.setSelectionMode(javax.swing.ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
        jScrollPane4.setViewportView(elemsTable);

        javax.swing.GroupLayout leftSidePanelLayout = new javax.swing.GroupLayout(leftSidePanel);
        leftSidePanel.setLayout(leftSidePanelLayout);
        leftSidePanelLayout.setHorizontalGroup(
            leftSidePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(leftSidePanelLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(leftSidePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                    .addComponent(jScrollPane3, javax.swing.GroupLayout.DEFAULT_SIZE, 278, Short.MAX_VALUE)
                    .addComponent(jLabel2, javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jLabel4, javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(javax.swing.GroupLayout.Alignment.LEADING, leftSidePanelLayout.createSequentialGroup()
                        .addComponent(jLabel1)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addComponent(nameTextField))
                    .addComponent(jScrollPane2, javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jScrollPane4, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 278, Short.MAX_VALUE)
                    .addGroup(javax.swing.GroupLayout.Alignment.LEADING, leftSidePanelLayout.createSequentialGroup()
                        .addComponent(createButton)
                        .addGap(53, 53, 53)
                        .addComponent(changeButton)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addComponent(updateButton))
                    .addComponent(jLabel3, javax.swing.GroupLayout.Alignment.LEADING))
                .addContainerGap())
        );
        leftSidePanelLayout.setVerticalGroup(
            leftSidePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(leftSidePanelLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(leftSidePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel1)
                    .addComponent(nameTextField))
                .addGap(13, 13, 13)
                .addComponent(jLabel2)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jLabel4)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jScrollPane4, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(leftSidePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(createButton)
                    .addComponent(updateButton)
                    .addComponent(changeButton))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(jLabel3)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jScrollPane3, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE))
        );

        detailsButton.setText("Details");
        detailsButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                detailsButtonActionPerformed(evt);
            }
        });

        deleteButton.setText("Delete");
        deleteButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                deleteButtonActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addComponent(leftSidePanel, javax.swing.GroupLayout.PREFERRED_SIZE, 298, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(detailsButton)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(deleteButton)
                        .addGap(0, 0, Short.MAX_VALUE))
                    .addComponent(envsScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 386, Short.MAX_VALUE))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addContainerGap()
                        .addComponent(envsScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 449, Short.MAX_VALUE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                            .addComponent(deleteButton)
                            .addComponent(detailsButton)))
                    .addComponent(leftSidePanel, javax.swing.GroupLayout.DEFAULT_SIZE, 489, Short.MAX_VALUE))
                .addContainerGap())
        );
    }// </editor-fold>//GEN-END:initComponents

    private void changeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_changeButtonActionPerformed
        int selectedRow = environmentsTable.getSelectedRow();
        if (selectedRow >= 0) {
            EnvironmentTo selectedEnv = ((EnvironmentTableModel) environmentsTable.getModel()).getSelectedEnvironment(selectedRow);
            descTextArea.setText(selectedEnv.getDescription());
            nameTextField.setText(selectedEnv.getName());
                        
            elemsTable.clearSelection();
            List<ElementTo> elemsList = ((ElementTableModel) elemsTable.getModel()).getElements();            
            for (ElementTo et : selectedEnv.getElements()){
                elemsTable.addRowSelectionInterval(elemsList.indexOf(et), elemsList.indexOf(et));
            }            
            
            outputTextArea.setText("Change attributes and click 'Update'\nto make changes permanent");
            updateButton.setEnabled(true);
            changeButton.setEnabled(false);
        } else {
            outputTextArea.setText("No environment is selected, or given environment \ndoes not exist!");
        }
    }//GEN-LAST:event_changeButtonActionPerformed

    private void createButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_createButtonActionPerformed
        Client client = ClientBuilder.newClient(cfg);
        WebTarget webTarget = client.target(restUrl);
        WebTarget resourceWebTarget = webTarget.path("environments/create");

        EnvironmentTo environmentTo = new EnvironmentTo();
        environmentTo.setDescription(descTextArea.getText());
        environmentTo.setName(nameTextField.getText());        
        environmentTo.setElements(getSelectedElems());
        
        if (!isEnvValid(environmentTo)){
            return;
        }

        Invocation.Builder invocationBuilder = resourceWebTarget.request(MediaType.APPLICATION_JSON);
        invocationBuilder.header("accept", "application/json");
        Entity<EnvironmentTo> entity = Entity.json(environmentTo);
        Response response = invocationBuilder.post(entity);
        int respStat = response.getStatus();
        System.out.println(respStat);
        if (respStat == 201) {
            descTextArea.setText("");
            nameTextField.setText("");
            initTable();
            outputTextArea.setText("Environment successfully created!");
            elemsTable.clearSelection();

        }
        if (respStat == 404) {
            outputTextArea.setText("Environment not created!");
        }
    }//GEN-LAST:event_createButtonActionPerformed

    private void detailsButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_detailsButtonActionPerformed
        int selectedRow = environmentsTable.getSelectedRow();
        if (selectedRow < 0) {
            outputTextArea.setText("No environment selected!");
            return;
        }
        EnvironmentTo selectedEnv = ((EnvironmentTableModel) environmentsTable.getModel()).getSelectedEnvironment(selectedRow);
        StringBuilder builder = new StringBuilder("Environment details: ");
        builder.append("\nID: ").append(selectedEnv.getId());
        builder.append("\nName: ").append(selectedEnv.getName());
        builder.append("\nDescription: ").append(selectedEnv.getDescription());
        for (ElementTo et : selectedEnv.getElements()){
            builder.append("\nElement: ").append(et.getType());
        }
        
        outputTextArea.setText(builder.toString());
    }//GEN-LAST:event_detailsButtonActionPerformed

    private void updateButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_updateButtonActionPerformed
        Client client = ClientBuilder.newClient(cfg);
        WebTarget webTarget = client.target(restUrl);
        WebTarget resourceWebTarget = webTarget.path("environments/update");

        Invocation.Builder invocationBuilder = resourceWebTarget.request(MediaType.APPLICATION_JSON);
        invocationBuilder.header("accept", "application/json");

        int selectedRow = environmentsTable.getSelectedRow();
        EnvironmentTo selectedEnv = ((EnvironmentTableModel) environmentsTable.getModel()).getSelectedEnvironment(selectedRow);

        selectedEnv.setDescription(descTextArea.getText());
        selectedEnv.setName(nameTextField.getText());
        selectedEnv.setElements(getSelectedElems());
        
        if (!isEnvValid(selectedEnv)){
            return;
        }

        Entity<EnvironmentTo> entity = Entity.json(selectedEnv);

        Response response = invocationBuilder.put(entity);
        int respStat = response.getStatus();

        if (respStat == 200) {
            descTextArea.setText("");
            nameTextField.setText("");
            outputTextArea.setText("Environment successfully updated!");
            ((EnvironmentTableModel) environmentsTable.getModel()).updateEnvironmentInTable(selectedEnv);
            elemsTable.clearSelection();
        }
        if (respStat == 404) {
            outputTextArea.setText(response.readEntity(String.class));
        }
    }//GEN-LAST:event_updateButtonActionPerformed

    private void deleteButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteButtonActionPerformed
        int selectedRow = environmentsTable.getSelectedRow();
        if (selectedRow < 0) {
            outputTextArea.setText("No environment selected!");
            return;
        }
        Client client = ClientBuilder.newClient(cfg);
        WebTarget webTarget = client.target(restUrl);
        WebTarget resourceWebTarget = webTarget.path("environments/delete/" + environmentsTable.getModel().getValueAt(environmentsTable.getSelectedRow(), ID_COLUMN_POSITION));

        Invocation.Builder invocationBuilder = resourceWebTarget.request(MediaType.APPLICATION_JSON);
        invocationBuilder.header("accept", "application/json");

        
        EnvironmentTo selectedEnv = ((EnvironmentTableModel) environmentsTable.getModel()).getSelectedEnvironment(selectedRow);

        Response response = invocationBuilder.delete();
        int respStat = response.getStatus();
        if (respStat == 200) {
            ((EnvironmentTableModel) environmentsTable.getModel()).deleteEnvironmentFromTable(selectedEnv);
            outputTextArea.setText("Envrionment successfully deleted!");
        } else {
            outputTextArea.setText("Environment cannot be deleted, some animals use it.");
        }
    }//GEN-LAST:event_deleteButtonActionPerformed


    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton changeButton;
    private javax.swing.JButton createButton;
    private javax.swing.JButton deleteButton;
    private javax.swing.JTextArea descTextArea;
    private javax.swing.JButton detailsButton;
    private javax.swing.JTable elemsTable;
    private javax.swing.JTable environmentsTable;
    private javax.swing.JScrollPane envsScrollPane;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel3;
    private javax.swing.JLabel jLabel4;
    private javax.swing.JScrollPane jScrollPane2;
    private javax.swing.JScrollPane jScrollPane3;
    private javax.swing.JScrollPane jScrollPane4;
    private javax.swing.JPanel leftSidePanel;
    private javax.swing.JTextField nameTextField;
    private javax.swing.JTextArea outputTextArea;
    private javax.swing.JButton updateButton;
    // End of variables declaration//GEN-END:variables

    private void disableButtons() {
        createButton.setEnabled(false);
        changeButton.setEnabled(false);
        deleteButton.setEnabled(false);
        descTextArea.setEnabled(false);
        detailsButton.setEnabled(false);
        environmentsTable.setEnabled(false);
        nameTextField.setEnabled(false);
        updateButton.setEnabled(false);
    }

    private List<ElementTo> getSelectedElems(){
        List<ElementTo> selectedElems = new ArrayList<>();
        int[] selectedRows = elemsTable.getSelectedRows();
        for (int i : selectedRows){
            selectedElems.add(((ElementTableModel) elemsTable.getModel()).getSelectedElement(i));
        }
        return selectedElems;
    }
    
    private boolean isEnvValid(EnvironmentTo environmentTo){
        boolean isValid = true;
        String errorMessage = "Some errors have been found:";
        if (environmentTo.getDescription().equals("")){
            errorMessage += "\nDescription cannot be empty.";
            isValid = false;
        }
        if (environmentTo.getName().equals("")){
            errorMessage += "\nName cannot be empty.";
            isValid = false;
        }
        if (environmentTo.getElements().isEmpty()){
            errorMessage += "\nSelect at least one element!";
            isValid = false;
        }
        if (!isValid){
            outputTextArea.setText(errorMessage);
        }
        return isValid;
    }
}
